package com.jacky.concurrent;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * Created by jacky on 2018/2/13.
 */
public class MySemaphore {

    private Sync sync;

    public MySemaphore(int permits){
       sync = new NonFairSync(permits);
    }

    public MySemaphore(int permits,boolean fair){
        sync = fair ? new FairSync(permits) : new NonFairSync(permits);
    }

    static class Sync extends AbstractQueuedSynchronizer{
        Sync(int permits) {
            setState(permits);
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            for (;;){
                int oldState = getState();
                int newState = oldState+arg;
                if (compareAndSetState(oldState,newState)){
                    return true;
                }

            }
        }
    }

    static final class FairSync extends Sync{
        FairSync(int permits) {
            super(permits);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            for(;;){
                if (hasQueuedPredecessors()){
                    return -1;
                }
                int oldState = getState();
                int newState = oldState-arg;
                if (newState <0 || compareAndSetState(oldState,newState)){
                    return  newState;
                }
            }
        }
    }

    static final class NonFairSync extends Sync{

        NonFairSync(int permits) {
            super(permits);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            for(;;){
                int oldState = getState();
                int newState = oldState-arg;
                if (newState <0 || compareAndSetState(oldState,newState)){
                    return  newState;
                }
            }
        }
    }

    /**
     * 获取许可证
     */
    public void acquire(){
        try {
            sync.acquireSharedInterruptibly(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放许可证
     */
    public void release(){
       sync.releaseShared(1);
    }


}
